<?php
namespace support\Util;

/**
 * 通用的树型类，可以生成任何树型结构
 */
error_reporting(E_ALL ^ E_NOTICE);
class InitTree
{
    /**
     * 生成树型结构所需要的2维数组
     * @var array
     */
    public $arr = array();

    /**
     * 生成树型结构所需修饰符号，可以换成图片
     * @var array
     */
    public $icon = array('│', '├', '└');

    /**
     * @access private
     */
    public $ret = '';

    /**
     * 构造函数，初始化类
     * @param array 2维数组，例如：
     * array(
     *      1 => array('id'=>'1','parentid'=>0,'name'=>'一级栏目一'),
     *      2 => array('id'=>'2','parentid'=>0,'name'=>'一级栏目二'),
     *      3 => array('id'=>'3','parentid'=>1,'name'=>'二级栏目一'),
     *      4 => array('id'=>'4','parentid'=>1,'name'=>'二级栏目二'),
     *      5 => array('id'=>'5','parentid'=>2,'name'=>'二级栏目三'),
     *      6 => array('id'=>'6','parentid'=>3,'name'=>'三级栏目一'),
     *      7 => array('id'=>'7','parentid'=>3,'name'=>'三级栏目二')
     *      )
     */
    public function set_tree($arr = array())
    {

        $this->arr = $arr;
        $this->ret = '';
        return is_array($arr);
    }

    /**
     * 得到父级数组
     * @param int
     * @return array
     */
    public function get_parent($myid)
    {
        $newarr = array();
        if (!isset($this->arr[$myid])) {
            return false;
        }

        $pid = $this->arr[$myid]['parentid'];
        return $this->detail($pid);
    }

    public function detail($id, $key = null)
    {
        $r = $this->arr[$id];
        return $key ? $r[$key] : $r;
    }

    /**
     * @param $list
     * @param StringService $pk
     * @param StringService $pid
     * @param StringService $child
     * @param int $root
     * @return array
     * @author: hhygyl
     * @name: listToTree
     * @describe:把返回的数据集转换成Tree
     */
    public  function listToTree($root)
    {
        $list  = $this->arr;
        $pk    = "id";
        $pid   = "parentid";
        $child = '_child';      
        // 创建Tree
        $tree = [];
        if (is_array($list)) {
            // 创建基于主键的数组引用
            $refer = array();
            foreach ($list as $key => $data) {
                $refer[$data[$pk]] = &$list[$key];
            }
            foreach ($list as $key => $data) {
                // 判断是否存在parent
                $parentId = $data[$pid];
                if ($root == $parentId) {
                    $tree[] = &$list[$key];
                } else {
                    if (isset($refer[$parentId])) {
                        $parent             = &$refer[$parentId];                      
                        $parent[$child][]   = &$list[$key];
                    }
                }
            }
        }

        return $tree;
    }

    /**
     * 得到子级数组
     * @param int
     * @return array
     */
    public function get_child($myid)
    {
        if (!$this->arr) {
            return false;
        }

        $a  = $newarr  = array();
        $ar = $this->arr;
        if (is_array($ar)) {

            foreach ($ar as $id => $a) {
                $sort[$id] = $a['order'] ? $a['order'] : 0;
            }

            $sort && array_multisort($sort, SORT_ASC, $ar);

            foreach ($ar as $id => $a) {
                if ($a['parentid'] == $myid) {
                    $newarr[$a['id']] = $a;
                }

            }
        }
        return $newarr ? $newarr : false;
    }

    /**
     * 得到子级数组
     * @param int
     * @return array
     */
    public function get_childs($myid, $level = 0)
    {
        if (!$this->arr) {
            return false;
        }

        $items = $this->arr;
        foreach ($items as $item) {
            $items[$item['parentid']]['son'][$item['id']] = &$items[$item['id']];
        }

        $r = isset($items[$myid]['son']) ? $items[$myid]['son'] : array();
        $r = self::array_multi2single($r, 0, $myid . ',');
        if ($myid):
            foreach ($r as $k => $v) {
                if (strpos($v['path'], $myid . ',') === false) {
                    unset($r[$k]);
                }

            }
        endif;

        return $r;
    }

    public function array_multi2single($array, $level = 0, $path = ',')
    {
        $result_array = array();
        foreach ($array as $k => $v) {
            $sort[$k] = $v['order'];
        }
        if ($sort) {
            array_multisort($sort, SORT_ASC, $array);
        }

        foreach ($array as $v) {
            $v['level'] = $level;
            $v['path']  = $path . $v['id'] . ',';
            if ($v['son'] && is_array($v['son'])) {
                $sub = $v['son'];
                unset($v['son']);
                $v['hasSub']            = 1;
                $result_array[$v['id']] = $v;
                $result_array += self::array_multi2single($sub, $level + 1, $v['path']);
            } else {
                $result_array[$v['id']] = $v;
            }

        }

        return $result_array;
    }

    /**
     * 得到根id
     * @param int
     * @return array
     */
    public function get_root_id($myid)
    {
        if (!isset($this->arr[$myid])) {
            return false;
        }

        $a[$myid] = $this->arr[$myid];
        $pid      = $this->arr[$myid]['parentid'];
        if ($pid == 0) {
            return $myid;
        }

        if (isset($this->arr[$pid])) {
            $root_id = $this->get_root_id($pid);
        }
        return $pid;
    }

    /**
     * 得到当前位置数组
     * @param int
     * @return array
     */
    public function get_pos($myid)
    {
        if (!isset($this->arr[$myid])) {
            return false;
        }

        $a[$myid] = $this->arr[$myid];

        $pid = $this->arr[$myid]['parentid'];
        if (isset($this->arr[$pid])) {
            $a += $this->get_pos($pid);
        }
        asort($a);
        return $a;
    }

    public function get_pos_ids($id)
    {
        return implode(',', array_keys($this->get_pos($id)));
    }
    /**
     * -------------------------------------
     *  得到树型结构
     * -------------------------------------
     * @author  Midnight(杨云洲),  yangyunzhou@foxmail.com
     * @param $myid 表示获得这个ID下的所有子级
     * @param $str 生成树形结构基本代码, 例如: "<option value=\$id \$select>\$spacer\$name</option>"
     * @param $sid 被选中的ID, 比如在做树形下拉框的时候需要用到
     * @param $adds
     * @param $str_group
     * @return unknown_type
     */
    public function get_tree($myid, $sid = 0, $adds = '', $str_group = '')
    {
        $r   = self::get_childs($myid, 0);
        $str = '';
        foreach ($r as $v) {
            $selected = ($sid == $v['id']) ? 'selected=selected' : '';
            $str .= '<option value=\'' . $v['id'] . '\' ' . $selected . ' >' . str_repeat('|—', $v['level']) . $v['name'] . '</option>';
        }
        return $str;
    }

    /**
     * 同上一方法类似,但允许多选
     */
    public function get_tree_multi($myid, $str, $sid = [], $adds = '')
    {
        $number = 1;
        $child  = $this->get_child($myid);
        if (is_array($child)) {
            $total = count($child);
            foreach ($child as $id => $a) {
                $j = $k = '';
                if ($number == $total) {
                    $j .= $this->icon[2];
                } else {
                    $j .= $this->icon[1];
                    $k = $adds ? $this->icon[0] : '';
                }
                $spacer = $adds ? $adds . $j : '';

                $selected = in_array($id, $sid) ? 'selected' : '';

                @extract($a);
                eval("\$nstr = \"$str\";");
                $this->ret .= $nstr;
                $this->get_tree_multi($id, $str, $sid, $adds . $k . '&nbsp;');
                $number++;
            }
        }
        return $this->ret;
    }

}
